package c_000_com

import (
	"fmt"
	"golang.org/x/net/html"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"unsafe"
)

// GetSliceAddr 返回slice的内存地址[计算每个元素的地址求和]
func GetSliceAddr(slice interface{}) string {
	sliceValue := reflect.ValueOf(slice)
	if sliceValue.Kind() != reflect.Slice {
		panic("Input is not a slice")
	}

	// 不能对比空slice
	if sliceValue.Len() == 0 {
		return "空slice"
	}

	// 获取slice底层数组的第一个元素的内存地址
	firstElementAddr := unsafe.Pointer(sliceValue.Index(0).UnsafeAddr())

	// 计算整个slice的内存地址
	sliceAddr := uintptr(firstElementAddr)

	return strconv.Itoa(int(sliceAddr))
}

func GetStructAddress(obj interface{}) string {
	v := reflect.ValueOf(obj)
	ptr := v.Pointer()
	return strconv.Itoa(int(ptr))
}

func GetHtmlTitle(url string) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	// Check Content-Type is HTML (e.g., "text/html;charset=utf-8").
	ct := resp.Header.Get("Content-Type")
	if ct != "text/html" && !strings.HasPrefix(ct, "text/html;") {
		resp.Body.Close()
		return fmt.Errorf("%s has type %s, not text/html", url, ct)
	}
	doc, err := html.Parse(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return fmt.Errorf("parsing %s as HTML: %v", url, err)
	}
	visitNode := func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "title" && n.FirstChild != nil {
			fmt.Println(n.FirstChild.Data)
		}
	}
	forEachNode(doc, visitNode, nil)
	return nil
}

// forEachNode针对每个结点x,都会调用pre(x)和post(x)。
// pre和post都是可选的。
// 遍历孩子结点之前,pre被调用
// 遍历孩子结点之后，post被调用
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
	if pre != nil {
		pre(n)
	}
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		forEachNode(c, pre, post)
	}
	if post != nil {
		post(n)
	}
}
